import { ExecutionContext } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { UnauthorizedException } from '@nestjs/common';
import type { JwtPayload } from '../../../types/auth';
import { Injectable } from '@nestjs/common';
export const TOKEN_SECRET_KEY = 'fanfan';
// 处理token的一个服务类
@Injectable()
export class HandleTokenService {
  constructor(private jwtService: JwtService) {}

  // JWT的配置密钥

  // ??? 取token的一个处理

  extractTokenFromHeader = (context: ExecutionContext): string | undefined => {
    // 拿到请求对象 - 使用正确的Express Request类型
    const request = context.switchToHttp().getRequest<Request>();

    // 检查authorization头是否存在
    const authorization = request.headers['authorization'];

    if (!authorization || typeof authorization !== 'string') {
      return undefined;
    }

    // 分割authorization头：格式为 "Bearer <token>"
    const parts = authorization.split(' ');

    // 确保格式正确：必须是 ["Bearer", "<token>"]
    if (parts.length !== 2 || parts[0] !== 'Bearer') {
      return undefined;
    }

    // 筛一遍 只保留Bearer类型的token
    const token = parts[1];
    return token || undefined;
  };

  // ??? 使用JWT对token进行验证
  verifyToken = async (token: string): Promise<JwtPayload> => {
    try {
      // 验证JWT token
      const payload = await this.jwtService.verifyAsync(token, {
        secret: TOKEN_SECRET_KEY,
      });

      // 检查payload是否存在且有效
      if (!payload) {
        throw new UnauthorizedException('用户信息不完整');
      }

      // 检查必需的字段是否存在
      if (!payload.username || !payload.id) {
        throw new UnauthorizedException('用户信息不完整');
      }

      // 检查token是否过期
      if (payload.exp && Date.now() / 1000 >= payload.exp) {
        throw new UnauthorizedException('登录过期，请重新登录');
      }

      return payload;
    } catch (error) {
      // 区分不同类型的JWT错误
      if (error instanceof UnauthorizedException) {
        throw error; // 直接重新抛出我们自定义的错误
      }

      // 处理JWT库抛出的具体错误
      if (error.name === 'JsonWebTokenError') {
        throw new UnauthorizedException('无效的登录凭证');
      } else if (error.name === 'TokenExpiredError') {
        throw new UnauthorizedException('登录过期，请重新登录');
      } else {
        throw new UnauthorizedException(`登录验证失败: ${error.message}`);
      }
    }
  };

  /**
   * 从HTTP请求中提取并验证JWT token的完整流程
   * @param context 执行上下文
   * @returns 验证后的JWT payload
   * @throws UnauthorizedException 当token无效时
   */
  extractAndVerifyToken = async (
    context: ExecutionContext
  ): Promise<boolean> => {
    // 1. 从请求头中提取token
    const token = this.extractTokenFromHeader(context);
    if (!token) {
      throw new UnauthorizedException('请先登录');
    }

    // 3. 验证token并将payload挂载到请求对象 下次使用时可以直接从请求对象中获取
    const request = context.switchToHttp().getRequest<Request>();
    request['user'] = await this.verifyToken(token);
    return true;
  };

  /**
   * 检查token是否即将过期（在指定时间内）
   * @param payload JWT payload
   * @param minutesBeforeExpiration 提前多少分钟检查（默认5分钟）
   * @returns 是否即将过期
   */
  isTokenExpiringSoon = (
    payload: JwtPayload,
    minutesBeforeExpiration: number = 5
  ): boolean => {
    if (!payload.exp) {
      return false; // 没有过期时间的token不检查
    }

    const now = Date.now() / 1000;
    const expirationTime = payload.exp;
    const warningTime = expirationTime - minutesBeforeExpiration * 60;

    return now >= warningTime;
  };

  /**
   * 获取token的剩余有效时间（秒）
   * @param payload JWT payload
   * @returns 剩余秒数，如果无过期时间则返回null
   */
  getTokenRemainingTime = (payload: JwtPayload): number | null => {
    if (!payload.exp) {
      return null; // 没有过期时间的token
    }

    const now = Date.now() / 1000;
    const remainingTime = payload.exp - now;

    return Math.max(0, Math.floor(remainingTime));
  };
}
